from fastapi import APIRouter, Request, WebSocket, Depends, Cookie
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from aiortc import RTCPeerConnection, RTCSessionDescription, RTCIceCandidate, MediaStreamTrack
from aiortc.contrib.media import MediaPlayer
import os
from core.logger import app_logger as logger
import asyncio
import json
import socket
from database import get_db, SessionLocal
from sqlalchemy.orm import Session
from models import Passage
import urllib.parse
from typing import Optional
from utils import validate_session  # 确保导入验证函数
from urllib.parse import unquote  # 导入 unquote 用于解码

# 创建路由器
router = APIRouter()

# 设置模板目录
templates = Jinja2Templates(directory="templates")

templates.env.filters["urldecode"] = unquote

# 获取有效的本地IP地址
def get_local_ip():
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        local_ip = s.getsockname()[0]
        s.close()
        logger.info(f"检测到本地IP地址: {local_ip}")
        return local_ip
    except Exception:
        logger.warning("无法检测本地IP地址, 使用默认值")
        return "0.0.0.0"

# 全局变量
LOCAL_IP = get_local_ip()
ICE_CANDIDATE = f"{LOCAL_IP}"

# 视频轨道类
class VideoStreamTrack(MediaStreamTrack):
    kind = "video"
    
    def __init__(self, player):
        super().__init__()
        self.player = player
        logger.debug("视频轨道已创建")
    
    async def recv(self):
        try:
            frame = await self.player.video.recv()
            return frame
        except Exception as e:
            logger.error(f"接收帧时出错: {str(e)}")
            raise

# 修改后的实时预览路由
@router.get("/realtime-preview", response_class=HTMLResponse)
async def realtime_preview_page(
    request: Request,
    SessionId: Optional[str] = Cookie(None),
    UserName: Optional[str] = Cookie(None),
    db: Session = Depends(get_db)
):
    """实时预览页面"""
    if not SessionId or not UserName or not validate_session(SessionId, UserName):
        return RedirectResponse(url="/")
    
    # 获取所有通道
    channels = db.query(Passage).filter(Passage.DeadTime.is_(None)).all()
    logger.info(f"查询到 {len(channels)} 个通道")
    
    return templates.TemplateResponse("realtime_preview.html", {
        "request": request,
        "UserName": UserName,
        "channels": channels,
        "ice_candidate": ICE_CANDIDATE
    })

# 保留原有的WebSocket路由
@router.websocket("/ws/video")
async def video_websocket(websocket: WebSocket):
    await websocket.accept()
    logger.info(f"WebSocket连接已建立: {websocket.client}")
    
    pc = None
    player = None
    rtsp_url = ""
    
    try:
        await websocket.send_text(json.dumps({
            "type": "ice_info",
            "ice_candidate": ICE_CANDIDATE
        }))
        
        while True:
            data = await websocket.receive_text()
            logger.debug(f"收到消息: {data}")
            
            try:
                message = json.loads(data)
            except json.JSONDecodeError:
                logger.error("无法解析JSON消息")
                continue
            
            if message.get("type") == "set_stream_url":
                rtsp_url = message["url"]
                rtsp_url = urllib.parse.unquote(rtsp_url)
                logger.info(f"更新RTSP流地址: {rtsp_url}")
                await websocket.send_text(json.dumps({
                    "type": "status",
                    "message": f"RTSP URL更新为: {rtsp_url}"
                })) 
                continue
                
            if message.get("type") == "offer" and rtsp_url:
                try:
                    pc = RTCPeerConnection()
                    logger.info(f"尝试播放RTSP流: {rtsp_url}")
                    
                    # 添加更详细的日志
                    logger.debug("创建MediaPlayer实例")
                    # 简化 MediaPlayer 选项
                    player = MediaPlayer(
                        rtsp_url,
                        format="rtsp",
                        options={
                            "rtsp_transport": "udp",
                            "fflags": "nobuffer",
                            "tune": "zerolatency",
                            "framedrop": "1"
                        }
                    )
                    
                    # 检查视频轨道是否可用
                    if not player.video:
                        logger.error("无法获取视频轨道")
                        await websocket.send_text(json.dumps({
                            "type": "error",
                            "message": "无法获取视频轨道"
                        }))
                        continue
                    
                    video_track = VideoStreamTrack(player)
                    pc.addTrack(video_track)
                    logger.info("视频轨道已添加到对等连接")
                    
                    @pc.on("icecandidate")
                    def on_icecandidate(candidate):
                        if candidate:
                            logger.debug(f"生成的本地ICE候选: {candidate.candidate}")
                            asyncio.run(websocket.send_text(json.dumps({
                                "type": "candidate",
                                "candidate": {
                                    "candidate": candidate.candidate,
                                    "sdpMid": candidate.sdpMid,
                                    "sdpMLineIndex": candidate.sdpMLineIndex
                                }
                            })))
                    # 添加带宽自适应逻辑
                    @pc.on("connectionstatechange")
                    async def on_connectionstatechange():
                        if pc.connectionState == "connected":
                            logger.info("连接已建立，开始监控带宽")
                            while True:
                                await asyncio.sleep(5)
                                stats = await pc.getStats()
                                # 根据带宽调整逻辑..
                        
                    offer = RTCSessionDescription(
                        sdp=message["offer"]["sdp"],
                        type=message["offer"]["type"]
                    )
                    await pc.setRemoteDescription(offer)
                    logger.info("远程描述已设置")
                    
                    answer = await pc.createAnswer()

                    # ===== 修复SDP格式问题 =====
                    sdp = answer.sdp
                    # 1. 移除问题行
                    sdp = sdp.replace("a=msid-semantic:WMS *\r\n", "")
                    # 2. 添加方向声明
                    sdp += "a=direction:sendrecv\r\n"
                    # 3. 创建新的answer对象
                    answer = RTCSessionDescription(sdp=sdp, type=answer.type)
                    # ===== 修复结束 =====

                    await pc.setLocalDescription(answer)
                    logger.info(f"创建应答: {answer.type}")
                    
                    await websocket.send_text(json.dumps({
                        "type": "answer",
                        "answer": {
                            "sdp": pc.localDescription.sdp,
                            "type": pc.localDescription.type
                        }
                    }))
                    logger.info("应答已发送")
                    
                except Exception as e:
                    logger.error(f"处理offer时出错: {str(e)}", exc_info=True)
                    await websocket.send_text(json.dumps({
                        "type": "error",
                        "message": f"处理offer失败: {str(e)}"
                    }))
                    continue
                
            elif message.get("type") == "candidate" and pc:
                try:
                    candidate_data = message["candidate"]["candidate"]
                    
                    if not candidate_data or candidate_data.lower() == "null":
                        logger.warning("收到无效ICE候选，跳过")
                        continue

                    parts = str(candidate_data).split(' ')
                    candidate = RTCIceCandidate(
                        foundation=parts[0],
                        component=int(parts[1]),
                        protocol=parts[2],
                        priority=int(parts[3]),
                        ip=parts[4],
                        port=int(parts[5]),
                        type=parts[7],
                        sdpMid=message["candidate"]["sdpMid"],
                        sdpMLineIndex=message["candidate"]["sdpMLineIndex"]
                    )
                    await pc.addIceCandidate(candidate)
                    logger.info("添加ICE候选成功")
                except Exception as e:
                    logger.error(f"解析ICE候选失败: {str(e)}")
                
    except Exception as e:
        logger.error(f"WebSocket错误: {str(e)}")
    finally:
        logger.info("关闭连接")
        try:
            if pc:
                await pc.close()
            if player:
                player.video.stop()
        except Exception as e:
            logger.error(f"关闭资源时出错: {str(e)}")
        await websocket.close()